home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / pcmagazi / 1992 / 12 / dlgdemo3.c < prev    next >
Text File  |  1992-04-30  |  30KB  |  784 lines

  1. //
  2. // DLGDEMO3 - Notepad Clone #3 demonstrating use of Win 3.1 Common Dialogs
  3. // Copyright (C) 1992 Ray Duncan
  4. // Ziff Davis Publishing Co. * PC Magazine
  5. //
  6.  
  7. #define WIN31
  8. #define dim(x) (sizeof(x) / sizeof(x[0]))   // returns no. of elements
  9. #define EXENAMESIZE 256                     // max length of path+filename
  10. #define BUFSIZE 65520                       // max length of file data
  11.  
  12. #include "string.h"
  13. #include "windows.h"
  14. #include "commdlg.h"
  15. #include "dlgdemo3.h"
  16.  
  17. HANDLE hInst;                               // module instance handle
  18. HWND hFrame;                                // handle for frame window
  19. HWND hEdit;                                 // handle for edit window
  20. char szFileName[EXENAMESIZE+1];             // name of current file 
  21. char szTemp[EXENAMESIZE+1];                 // filename scratch buffer
  22. int hFile;                                  // handle for current file
  23. HANDLE hBuff;                               // handle for file I/O buffer
  24. LPSTR lpBuff;                               // far pointer to file buffer
  25. DWORD dwColor = RGB(0, 0, 0);               // user-selected colorref
  26.             
  27.                                             // for FindText & ReplaceText
  28. FINDREPLACE fr;                             // common dialog data structure
  29. HWND hFindDlg = (HWND) 0;                   // nomodal dialog handle
  30. char szFind[256];                           // text to find
  31. char szReplace[256];                        // text to replace
  32.  
  33. char szShortAppName[] = "DlgDemo";          // short application name
  34. char szAppName[] = "Common Dialog Demo #3"; // long application name
  35. char szMenuName[] = "DlgDemoMenu";          // name of menu resource
  36. char szDefName[] = "UNTITLED";              // default filename
  37. char szDefExt[] = "TXT";                    // default extension
  38.  
  39. char *szFilter[] = {                        // filters for Open and
  40.     "ASCII Text (*.TXT)", "*.TXT",          // SaveAs common dialogs
  41.     "All Files (*.*)", "*.*",
  42.     "" };
  43.  
  44. struct decodeWord {                         // structure associates
  45.     WORD Code;                              // messages or menu IDs
  46.     LONG (*Fxn)(HWND, WORD, WORD, LONG); }; // with a function
  47.  
  48. //
  49. // Table of window messages supported by FrameWndProc()
  50. // and the functions which correspond to each message.
  51. //
  52. struct decodeWord messages[] = {
  53.     0, DoFindReplace,
  54.     WM_CREATE, DoCreate,
  55.     WM_INITMENU, DoInitMenu,
  56.     WM_SETFOCUS, DoSetFocus,
  57.     WM_SIZE, DoSize,
  58.     WM_COMMAND, DoCommand,
  59.     WM_DESTROY, DoDestroy, 
  60.     WM_CTLCOLOR, DoSetColor, } ;
  61.  
  62. //
  63. // Table of menubar item IDs and their corresponding functions.
  64. //
  65. struct decodeWord menuitems[] = {
  66.     IDM_NEW, DoMenuNew,
  67.     IDM_OPEN, DoMenuOpen,
  68.     IDM_SAVE, DoMenuSave,
  69.     IDM_SAVEAS, DoMenuSaveAs,
  70.     IDM_EXIT, DoMenuExit, 
  71.     IDM_UNDO, DoMenuUndo,
  72.     IDM_CUT, DoMenuCut,
  73.     IDM_COPY, DoMenuCopy,
  74.     IDM_PASTE, DoMenuPaste,
  75.     IDM_DELETE, DoMenuDelete, 
  76.     IDM_FIND, DoMenuFind,
  77.     IDM_REPLACE, DoMenuReplace,
  78.     IDM_FONT, DoMenuFont,
  79.     IDM_COLOR, DoMenuColor, } ;
  80.  
  81. //
  82. // WinMain -- entry point for this application from Windows.
  83. //
  84. int PASCAL WinMain(HANDLE hInstance,
  85.     HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  86. {
  87.     MSG msg;
  88.  
  89.     hInst = hInstance;                      // save this instance handle
  90.  
  91.     if(!hPrevInstance)                      // if first instance,
  92.         if(!InitApplication(hInstance))     // register window class
  93.         {
  94.             MessageBox(hFrame, "Can't initialize application!", szAppName, 
  95.                 MB_ICONSTOP|MB_OK);
  96.             return(FALSE);
  97.         }
  98.  
  99.     if(!InitInstance(hInstance, nCmdShow))  // create this instance's window
  100.     {
  101.         MessageBox(hFrame, "Can't initialize instance!", szAppName, 
  102.             MB_ICONSTOP|MB_OK);
  103.         return(FALSE);
  104.     }
  105.  
  106.     while(GetMessage(&msg, NULL, 0, 0))     // while message != WM_QUIT
  107.     {
  108.         if((hFindDlg == 0) || !IsDialogMessage(hFindDlg, &msg))
  109.         {
  110.             TranslateMessage(&msg);         // translate virtual key codes
  111.             DispatchMessage(&msg);          // dispatch message to window
  112.         }
  113.     }
  114.  
  115.     TermInstance(hInstance);                // clean up for this instance
  116.     return(msg.wParam);                     // return code = WM_QUIT value
  117. }
  118.  
  119. //
  120. // InitApplication --- global initialization code for this application.
  121. //
  122. BOOL InitApplication(HANDLE hInstance)
  123. {
  124.     WNDCLASS  wc;
  125.  
  126.     // set parameters for frame window class
  127.     wc.style = CS_HREDRAW|CS_VREDRAW;       // class style
  128.     wc.lpfnWndProc = FrameWndProc;          // class callback function
  129.     wc.cbClsExtra = 0;                      // extra per-class data
  130.     wc.cbWndExtra = 0;                      // extra per-window data
  131.     wc.hInstance = hInstance;               // handle of class owner
  132.     wc.hIcon = LoadIcon(hInst, "DlgDemoIcon");      // application icon
  133.     wc.hCursor = LoadCursor(NULL, IDC_ARROW);       // default cursor
  134.     wc.hbrBackground = GetStockObject(WHITE_BRUSH); // background color 
  135.     wc.lpszMenuName =  szMenuName;          // name of menu resource
  136.     wc.lpszClassName = szShortAppName;      // name of window class
  137.  
  138.     return(RegisterClass(&wc));             // register class, return status
  139. }
  140.  
  141. //
  142. // InitInstance --- instance initialization code for this application.
  143. //
  144. BOOL InitInstance(HANDLE hInstance, WORD nCmdShow)
  145. {
  146.     hFrame = CreateWindow(                  // create frame window
  147.         szShortAppName,                     // window class name
  148.         szAppName,                          // text for title bar
  149.         WS_OVERLAPPEDWINDOW,                // window style
  150.         CW_USEDEFAULT, CW_USEDEFAULT,       // default position
  151.         CW_USEDEFAULT, CW_USEDEFAULT,       // default size
  152.         NULL,                               // no parent window
  153.         NULL,                               // use class default menu
  154.         hInstance,                          // window owner
  155.         NULL);                              // unused pointer
  156.  
  157.     if(!hFrame) return(FALSE);              // error, can't create window
  158.  
  159.     hBuff = GlobalAlloc(GMEM_MOVEABLE, BUFSIZE);    // allocate memory
  160.     if(!hBuff)                                      // abort if no memory
  161.     {
  162.         MessageBox(hFrame, "Can't allocate memory!", szAppName, 
  163.             MB_ICONSTOP|MB_OK);
  164.         return(0);
  165.     }
  166.  
  167.     lpBuff = GlobalLock(hBuff);             // get far pointer to memory
  168.  
  169.     // register message for FindText() and ReplaceText() common dialogs
  170.     messages[0].Code = RegisterWindowMessage((LPSTR) FINDMSGSTRING);
  171.  
  172.     ShowWindow(hFrame, nCmdShow);           // make frame window visible
  173.     UpdateWindow(hFrame);                   // force WM_PAINT message
  174.     SendMessage(hFrame, WM_COMMAND,         // force new (empty) file by 
  175.         IDM_NEW, 0L);                       // simulating File-New command
  176.     return(TRUE);                           // return success flag
  177. }
  178.  
  179. //
  180. // TermInstance -- instance termination code for this application.
  181. //
  182. BOOL TermInstance(HANDLE hinstance)
  183. {
  184.     GlobalUnlock(hBuff);                    // unlock the memory buffer
  185.     GlobalFree(hBuff);                      // release the buffer
  186.     return(TRUE);                           // return success flag
  187. }
  188.  
  189. //
  190. // FrameWndProc --- callback function for application frame window.
  191. //
  192. LONG FAR PASCAL FrameWndProc(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  193. {
  194.     int i;                                  // scratch variable
  195.  
  196.     for(i = 0; i < dim(messages); i++)      // decode window message and
  197.     {                                       // run corresponding function
  198.         if(wMsg == messages[i].Code)
  199.             return((*messages[i].Fxn)(hWnd, wMsg, wParam, lParam));
  200.     }
  201.  
  202.     return(DefWindowProc(hWnd, wMsg, wParam, lParam));
  203. }
  204.  
  205. //
  206. // DoCreate -- process WM_CREATE message for frame window by
  207. // creating a multiline edit control that will fill the frame window.
  208. // 
  209. LONG DoCreate(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  210. {
  211.     hEdit = CreateWindow("edit",            // class name
  212.                 NULL,                       // text for title bar 
  213.                 WS_CHILD|WS_VISIBLE|WS_HSCROLL|     
  214.                 WS_VSCROLL|WS_BORDER|ES_LEFT|ES_MULTILINE| 
  215.                 ES_AUTOHSCROLL|ES_AUTOVSCROLL,  // window style
  216.                 0, 0,                       // window position
  217.                 0, 0,                       // window size
  218.                 hWnd,                       // parent window
  219.                 IDE_MLE,                    // edit control ID
  220.                 hInst,                      // window owner
  221.                 NULL);                      // unused pointer
  222.     return(0);
  223. }
  224.  
  225. //
  226. // DoSetFocus -- process WM_SETFOCUS message for frame window.
  227. // 
  228. LONG DoSetFocus(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  229. {
  230.     SetFocus(hEdit);                        // toss the focus to 
  231.     return(0);                              // multiline edit control
  232. }
  233.  
  234. //
  235. // DoSize -- process WM_SIZE message for frame window by resizing
  236. // the multiline edit control to completely fill the client area.
  237. // 
  238. LONG DoSize(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  239. {
  240.     MoveWindow(hEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
  241.     return(0);
  242. }
  243.  
  244. //
  245. // DoDestroy -- process WM_DESTROY message for frame window.
  246. // 
  247. LONG DoDestroy(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  248. {
  249.     PostQuitMessage(0);                     // force WM_QUIT message to
  250.     return(0);                              // terminate the event loop
  251. }
  252.  
  253. //
  254. // DoSetColor -- process WM_CTLCOLOR message for edit window.
  255. // 
  256. LONG DoSetColor(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  257. {
  258.     SetTextColor((HDC) wParam, dwColor);    // set text color from results
  259.     return(GetStockObject(WHITE_BRUSH));    // return background brush handle
  260. }
  261.  
  262. //
  263. // DoFindReplace -- process WM_FINDMSGSTRING message from nonmodal
  264. // FindText() AND ReplaceText() common dialogs.  Dispatch DoFind()
  265. // or DoReplace() according to flags in FINDREPLACE structure.
  266. //
  267. LONG DoFindReplace(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  268. {
  269.     if(fr.Flags & FR_DIALOGTERM)            // is dialog being destroyed?
  270.     {
  271.         hFindDlg = 0;                       // yes, reset window handle
  272.         return(0);                          // allowing another dialog
  273.     }                                       // be created
  274.  
  275.     if(fr.Flags & FR_FINDNEXT)              // no, perform find or replace
  276.         return(DoFind(hWnd, wMsg, wParam, lParam));
  277.     else if(fr.Flags & (FR_REPLACE | FR_REPLACEALL))
  278.         return(DoReplace(hWnd, wMsg, wParam, lParam));
  279.     else
  280.         return(DefWindowProc(hWnd, wMsg, wParam, lParam));
  281. }
  282.  
  283. //
  284. // DoFind -- process find command from modeless FindText dialog
  285. //
  286. LONG DoFind(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  287. {
  288.     if(!FindString())                       // search for string
  289.         MessageBox(hFrame,                  // complain if no match
  290.             "Can't find string!", szAppName, MB_ICONSTOP | MB_OK);
  291.     SetFocus(hEdit);                        // restore input focus
  292.     return(0);
  293. }
  294.  
  295. //
  296. // DoReplace -- process replace or replace-all command from 
  297. // modeless FindReplace dialog
  298. //
  299. LONG DoReplace(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  300. {
  301.     int i = 0;                              // replacement counter
  302.     char buff[80];                          // scratch buffer
  303.  
  304.     if(fr.Flags & FR_REPLACEALL)            // replace multiple?
  305.     {
  306.         while(FindString())                 // yes, while another match 
  307.         {                                   // exists, replace it
  308.             SendMessage(hEdit, EM_REPLACESEL, 0, (LPSTR) szReplace);
  309.             i++;                            // and count replacements   
  310.             
  311.         }
  312.  
  313.         wsprintf(buff, "%d replacements made.", i);
  314.         MessageBox(hFrame,                  // show counter to user
  315.                 buff, szAppName, MB_ICONEXCLAMATION | MB_OK);
  316.  
  317.     }
  318.     else                                    // this is single replace
  319.     {
  320.         if(!FindString())                   // search for string
  321.             MessageBox(hFrame,              // complain if no match
  322.                 "Can't find string!", szAppName, MB_ICONSTOP | MB_OK);
  323.         else                                // otherwise replace it
  324.             SendMessage(hEdit, EM_REPLACESEL, 0, (LPSTR) szReplace);
  325.     }
  326.  
  327.     SetFocus(hEdit);                        // restore input focus
  328.     return(0);
  329. }
  330.  
  331. //
  332. // FindString -- search edit control from current selection point for
  333. // the string in szFind[].  If string is present, set selection to include
  334. // match and return TRUE, otherwise return FALSE.
  335. //
  336. BOOL FindString(VOID)
  337. {
  338.     LONG sel;                               // current selection
  339.     int begSel, endSel, cText, cSch;        // scratch variables
  340.     int schDir = 1;                         // search direction
  341.     PSTR pText, pWork;                      // scratch pointers
  342.     HANDLE hText;                           // local heap handle
  343.     int (*matcher)(PSTR, PSTR, WORD);       // pointer to match function
  344.  
  345.     // get handle for memory block, convert to pointer, get text length
  346.     hText = (HANDLE) SendMessage(hEdit, EM_GETHANDLE, 0, 0L);
  347.     pText = LocalLock(hText);
  348.     cText = (WORD) SendMessage (hEdit, WM_GETTEXTLENGTH, 0, 0L);
  349.  
  350.     if(cText == 0) return(FALSE);           // bail out if no text at all
  351.  
  352.     // get offset of beginning and end of current selection
  353.     sel = SendMessage(hEdit, EM_GETSEL, 0, 0L);
  354.     begSel = LOWORD(sel);
  355.     endSel = HIWORD(sel);
  356.  
  357.     // set search direction from flags in FINDREPLACE structure
  358.     schDir = fr.Flags & FR_DOWN ? 1 : -1 ;  
  359.  
  360.     // select case-sensitive or case-insensitive match function
  361.     matcher = fr.Flags & FR_MATCHCASE ? strncmp : strnicmp;
  362.  
  363.     // calculate search starting point within text block
  364.     pWork = pText + begSel + schDir;    
  365.  
  366.     // calculate length of text to search
  367.     cSch = schDir<1 ? begSel : max(cText-begSel+1-strlen(szFind), 0);
  368.  
  369.     while(cSch > 0)                         // search until match found
  370.     {                                       // or text is exhausted
  371.         if((*matcher)(pWork, szFind, strlen(szFind)) == 0)
  372.         {
  373.             LocalUnlock(hText);             // found a match, select it
  374.             begSel = pWork - pText;
  375.             endSel = begSel + strlen(szFind);
  376.             SendMessage(hEdit, EM_SETSEL, 0, MAKELONG(begSel, endSel));
  377.             return(TRUE);                   // return success flag
  378.         }
  379.  
  380.         cSch--;                             // no match yet, adjust text
  381.         pWork += schDir;                    // address & length remaining
  382.     }
  383.  
  384.     LocalUnlock(hText);                     // unlock edit control text
  385.     return(FALSE);                          // return match failed flag
  386. }
  387.  
  388. //
  389. // DoInitMenu - initialize the items on menu bar according to the 
  390. // state of the multiline edit control.  If nothing is selected, the 
  391. // edit-cut/copy/delete items are greyed out.  If nothing has 
  392. // been changed since the last file read or write, the file-save item
  393. // is greyed out.  If no text is in the clipboard, the edit-paste
  394. // item is greyed out.
  395. //
  396. LONG DoInitMenu(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  397. {
  398.     LONG selection;
  399.     
  400.     selection = SendMessage(hEdit, EM_GETSEL, 0, 0);
  401.  
  402.     if(HIWORD(selection) != LOWORD(selection))          // set cut/copy/
  403.     {                                                   // delete status
  404.         EnableMenuItem(wParam, IDM_CUT, MF_ENABLED);    
  405.         EnableMenuItem(wParam, IDM_COPY, MF_ENABLED);   
  406.         EnableMenuItem(wParam, IDM_DELETE, MF_ENABLED); 
  407.     }
  408.     else
  409.     {
  410.         EnableMenuItem(wParam, IDM_CUT, MF_GRAYED); 
  411.         EnableMenuItem(wParam, IDM_COPY, MF_GRAYED);    
  412.         EnableMenuItem(wParam, IDM_DELETE, MF_GRAYED);  
  413.     }
  414.  
  415.     if(SendMessage(hEdit, EM_CANUNDO, 0, 0))            // set undo status
  416.         EnableMenuItem(wParam, IDM_UNDO, MF_ENABLED);   
  417.     else
  418.         EnableMenuItem(wParam, IDM_UNDO, MF_GRAYED);    
  419.  
  420.     if(IsClipboardFormatAvailable(CF_TEXT))             // set paste status
  421.         EnableMenuItem(wParam, IDM_PASTE, MF_ENABLED);  
  422.     else
  423.         EnableMenuItem(wParam, IDM_PASTE, MF_GRAYED);   
  424.  
  425.     if(SendMessage(hEdit, EM_GETMODIFY, 0, 0))          // set save status
  426.         EnableMenuItem(wParam, IDM_SAVE, MF_ENABLED);   
  427.     else
  428.         EnableMenuItem(wParam, IDM_SAVE, MF_GRAYED);    
  429.     
  430.     // disable find & replace if modeless dialog already active
  431.     if(hFindDlg)                                           
  432.     {                                                   
  433.         EnableMenuItem(wParam, IDM_FIND, MF_GRAYED);    
  434.         EnableMenuItem(wParam, IDM_REPLACE, MF_GRAYED); 
  435.     }                                                   
  436.     else
  437.     {                                                   
  438.         EnableMenuItem(wParam, IDM_FIND, MF_ENABLED);    
  439.         EnableMenuItem(wParam, IDM_REPLACE, MF_ENABLED);    
  440.     }
  441.  
  442.     return(0);
  443. }
  444.  
  445. //
  446. // DoCommand -- process WM_COMMAND message for frame window by
  447. // decoding the menubar item with the menuitems[] array, then
  448. // running the corresponding function to process the command.
  449. // 
  450. LONG DoCommand(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  451. {
  452.     int i;                                  // scratch variable
  453.  
  454.     if((wParam == IDE_MLE) && (HIWORD(lParam) == EN_ERRSPACE))
  455.     {
  456.         MessageBox(hWnd, "Out of memory!", "Common Dialog Demo", 
  457.             MB_OK | MB_ICONSTOP);
  458.         return(0);
  459.     }
  460.  
  461.     for(i = 0; i < dim(menuitems); i++)     // decode menu command and
  462.     {                                       // run corresponding function
  463.         if(wParam == menuitems[i].Code)
  464.             return((*menuitems[i].Fxn)(hWnd, wMsg, wParam, lParam));
  465.     }
  466.  
  467.     return(DefWindowProc(hWnd, wMsg, wParam, lParam));
  468. }
  469.  
  470. //
  471. // DoMenuNew -- process File-New command from menu bar.
  472. // 
  473. LONG DoMenuNew(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  474. {
  475.     QueryWriteFile(hEdit);                  // check for dirty buffer
  476.     NewFile(hEdit);                         // empty the text window
  477.     return(0);
  478. }
  479.  
  480. //
  481. // DoMenuOpen -- process File-Open command from menu bar.
  482. //
  483. LONG DoMenuOpen(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  484. {
  485.     OPENFILENAME ofn;                       // used by common dialogs
  486.  
  487.     QueryWriteFile(hEdit);                  // check for dirty buffer
  488.  
  489.     szTemp[0]  = '\0';                      // init filename buffer
  490.  
  491.     ofn.lStructSize = sizeof(OPENFILENAME); // length of structure
  492.     ofn.hwndOwner = hWnd;                   // handle for owner window
  493.     ofn.lpstrFilter = szFilter[0];          // address of filter list
  494.     ofn.lpstrCustomFilter = NULL;           // custom filter buffer address
  495.     ofn.nFilterIndex = 1;                   // use *.TXT filter
  496.     ofn.lpstrFile = szTemp;                 // buffer for path+filename
  497.     ofn.nMaxFile = EXENAMESIZE;             // length of buffer
  498.     ofn.lpstrFileTitle = NULL;              // buffer for filename only
  499.     ofn.lpstrInitialDir = NULL;             // initial directory for dialog
  500.     ofn.lpstrTitle = NULL;                  // title for dialog box
  501.     ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
  502.     ofn.lpstrDefExt = NULL;                 // default extension 
  503.  
  504.     if(GetOpenFileName(&ofn))               // display open dialog, 
  505.         ReadFile(hEdit);                    // read data from file
  506.  
  507.     return(0);
  508. }
  509.  
  510. //
  511. // DoMenuSave -- Process File-Save command from menu bar.  If
  512. // filename is default (UNTITLED), ask user for a different one.
  513. //
  514. LONG DoMenuSave(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  515. {
  516.     int hFile;                              // scratch file handle
  517.  
  518.     if(strcmp(szFileName, szDefName) == 0)  // if default name, use SaveAs
  519.         SendMessage(hFrame, WM_COMMAND, IDM_SAVEAS, 0);
  520.     else
  521.         WriteFile(hEdit);                   // otherwise write data to file
  522.  
  523.     return(0);
  524. }
  525.  
  526. //
  527. // DoMenuSaveAs -- process File-SaveAs command from menu bar.
  528. // 
  529. LONG DoMenuSaveAs(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  530. {
  531.     OPENFILENAME ofn;                       // used by common dialogs
  532.  
  533.     strcpy(szTemp, szFileName);             // get default filename
  534.  
  535.     ofn.lStructSize = sizeof(OPENFILENAME); // length of structure
  536.     ofn.hwndOwner = hWnd;                   // handle of owner window
  537.     ofn.lpstrFilter = szFilter[0];          // address of filter list
  538.     ofn.lpstrCustomFilter = NULL;           // custom filter buffer address
  539.     ofn.nFilterIndex = 1L;                  // use *.TXT filter
  540.     ofn.lpstrFile = szTemp;                 // buffer for path+filename
  541.     ofn.nMaxFile = EXENAMESIZE;             // size of buffer
  542.     ofn.lpstrFileTitle = NULL;              // buffer for filename only
  543.     ofn.lpstrInitialDir = NULL;             // initial directory for dialog
  544.     ofn.lpstrTitle = NULL;                  // title for dialog box
  545.     ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOTESTFILECREATE;
  546.     ofn.lpstrDefExt = szDefExt;             // default extension
  547.  
  548.     if(GetSaveFileName(&ofn))               // display save-as dialog,
  549.         WriteFile(hEdit);                   // write data to file
  550.  
  551.     return(0);                          
  552. }
  553.  
  554. //
  555. // DoMenuExit -- process File-Exit command from menu bar.
  556. // 
  557. LONG DoMenuExit(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  558. {
  559.     QueryWriteFile(hEdit);                  // check for dirty buffer
  560.     SendMessage (hWnd, WM_CLOSE, 0, 0L);    // send window close message    
  561.     return(0);                              // to shut down the app
  562. }
  563.  
  564. //
  565. // DoMenuUndo -- process Edit-Undo command from menu bar.
  566. // 
  567. LONG DoMenuUndo(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  568. {
  569.     SendMessage(hEdit, WM_UNDO, 0, 0);      // tell the edit control
  570.     return(0);
  571. }
  572.  
  573. //
  574. // DoMenuCut -- process Edit-Cut command from menu bar.
  575. // 
  576. LONG DoMenuCut(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  577. {
  578.     SendMessage(hEdit, WM_CUT, 0, 0);       // tell the edit control
  579.     return(0);
  580. }
  581.  
  582. //
  583. // DoMenuCopy -- process Edit-Copy command from menu bar.
  584. // 
  585. LONG DoMenuCopy(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  586. {
  587.     SendMessage(hEdit, WM_COPY, 0, 0);      // tell the edit control
  588.     return(0);
  589. }
  590.  
  591. //
  592. // DoMenuPaste -- process Edit-Paste command from menu bar.
  593. // 
  594. LONG DoMenuPaste(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  595. {
  596.     SendMessage(hEdit, WM_PASTE, 0, 0);     // tell the edit control
  597.     return(0);
  598. }
  599.  
  600. //
  601. // DoMenuDelete -- process Edit-Delete command from menu bar.
  602. // 
  603. LONG DoMenuDelete(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  604. {
  605.     SendMessage(hEdit, WM_CLEAR, 0, 0);     // tell the edit control
  606.     return(0);
  607. }
  608.  
  609. //
  610. // DoMenuFind -- process Search-Find command from menu bar.
  611. // 
  612. LONG DoMenuFind(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  613. {
  614.     fr.lStructSize = sizeof(FINDREPLACE);   // length of structure
  615.     fr.hwndOwner = hWnd;                    // handle of owner window
  616.     fr.Flags = FR_DOWN | FR_HIDEWHOLEWORD;  // option flags
  617.     fr.lpstrFindWhat = szFind;              // string to find
  618.     fr.wFindWhatLen = sizeof(szFind);       // length of find buffer
  619.  
  620.     hFindDlg = FindText(&fr);               // activate FindText dialog
  621.     return(0);
  622. }
  623.  
  624. //
  625. // DoMenuReplace -- process Search-Replace command from menu bar.
  626. // 
  627. LONG DoMenuReplace(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  628. {
  629.     fr.lStructSize = sizeof(FINDREPLACE);   // length of structure
  630.     fr.hwndOwner = hWnd;                    // handle of owner window
  631.     fr.Flags = FR_DOWN | FR_HIDEWHOLEWORD;  // option flags
  632.     fr.lpstrFindWhat = szFind;              // string to find
  633.     fr.wFindWhatLen = sizeof(szFind);       // length of find buffer
  634.     fr.lpstrReplaceWith = szReplace;        // replacement string
  635.     fr.wReplaceWithLen = sizeof(szReplace); // length of replace buffer
  636.  
  637.     hFindDlg = ReplaceText(&fr);            // activate ReplaceText dialog
  638.     return(0);
  639. }
  640.  
  641. //
  642. // DoMenuFont -- process Font command from menu bar.
  643. // 
  644. LONG DoMenuFont(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  645. {
  646.     LOGFONT lf;                             // logical font data structure
  647.     CHOOSEFONT chf;                         // font dialog data structure
  648.     HFONT hfont;                            // logical font handle
  649.  
  650.     chf.lStructSize = sizeof(CHOOSEFONT);   // size of structure    
  651.     chf.hwndOwner = hWnd;                   // window handle of owner
  652.     chf.lpLogFont = &lf;                    // logical font structure
  653.     chf.Flags = CF_SCREENFONTS|CF_EFFECTS;  // option flags
  654.     chf.rgbColors = RGB(0,0,0);             // default color = black
  655.  
  656.     if(ChooseFont(&chf))                    // display ChooseFont dialog    
  657.     {
  658.         hfont = CreateFontIndirect(&lf);    // save font handle, then send 
  659.         SendMessage(hEdit, WM_SETFONT, hfont, TRUE);  // it to edit control
  660.     }
  661.  
  662.     return(0);
  663. }
  664.  
  665. //
  666. // DoMenuColor -- process Color command from menu bar.
  667. // 
  668. LONG DoMenuColor(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  669. {
  670.     CHOOSECOLOR chc;                        // color dialog data structure
  671.     DWORD dwCustColors[16];                 // array of custom colorrefs
  672.     int i;                                  // scratch variable
  673.  
  674.     for(i = 0; i < 16; i++)                 // init custom colors to white
  675.         dwCustColors[i] = RGB(255, 255, 255);
  676.  
  677.     chc.lStructSize = sizeof(CHOOSECOLOR);  // size of structure
  678.     chc.hwndOwner = hWnd;                   // window handle of owner
  679.     chc.rgbResult = dwColor;                // initial color to select
  680.     chc.lpCustColors = dwCustColors;        // addr of custom color array
  681.     chc.Flags = CC_FULLOPEN | CC_RGBINIT;   // option flags
  682.  
  683.     if(ChooseColor(&chc))                   // display ChooseColor dialog
  684.     {
  685.         dwColor = chc.rgbResult;            // save new text color
  686.         InvalidateRect(hEdit, NULL, TRUE);  // then force edit window to
  687.         UpdateWindow(hEdit);                // be redrawn with new color
  688.     }
  689.  
  690.     return(0);
  691. }
  692.  
  693. //
  694. // NewFile -- set empty text window with default filename.
  695. //
  696. VOID NewFile(HANDLE hEdit)
  697. {
  698.     lpBuff[0] = '\0';                       // empty the edit control
  699.     SetWindowText(hEdit, lpBuff);           // put text into window
  700.     strcpy(szFileName, szDefName);          // set default filename
  701.     SetWindowCaption(szFileName);           // update title bar
  702.     SendMessage(hEdit, EM_SETMODIFY, 0, 0); // clear change flag
  703. }
  704.  
  705. //
  706. // ReadFile -- read text from specified file to window, close file.
  707. //
  708. VOID ReadFile(HANDLE hEdit)
  709. {
  710.     int length;                             // scratch variable
  711.     int hFile;                              // scratch file handle
  712.  
  713.     hFile = _lopen(szTemp, OF_READ);        // try and open the file
  714.     if(hFile == -1)                         // bail out if no such file
  715.     {
  716.         MessageBox(hFrame, "Can't open file!", szAppName, MB_ICONSTOP|MB_OK);
  717.         return;
  718.     }
  719.  
  720.     strcpy(szFileName, szTemp);             // save new filename
  721.     length = _lread(hFile, lpBuff, BUFSIZE);    // read the file
  722.     lpBuff[length] = '\0';                  // make text ASCIIZ
  723.     SetWindowText(hEdit, lpBuff);           // put text into window
  724.     _lclose(hFile);                         // close the file
  725.     SetWindowCaption(szFileName);           // update title bar
  726.     SendMessage(hEdit, EM_SETMODIFY, 0, 0); // clear change flag
  727. }
  728.  
  729. //
  730. // WriteFile -- write text from specified window to file, close file.
  731. //
  732. VOID WriteFile(HANDLE hEdit)
  733. {
  734.     int length;                             // scratch variable
  735.     int hFile;                              // scratch file handle
  736.  
  737.     hFile = _lcreat(szTemp, 0);             // try and create the file
  738.     if(hFile == -1)                         // bail out if create failed
  739.     {
  740.         MessageBox(hFrame, "Can't create file!", szAppName, 
  741.             MB_ICONSTOP|MB_OK);
  742.         return;
  743.     }
  744.  
  745.     strcpy(szFileName, szTemp);             // save new filename
  746.     length = GetWindowTextLength(hEdit);    // chars in edit control
  747.     GetWindowText(hEdit, lpBuff, length+1); // retrieve text
  748.     _lwrite(hFile, lpBuff, length);         // write text to file
  749.     _lclose(hFile);                         // close the file
  750.     SetWindowCaption(szFileName);           // update title bar
  751.     SendMessage(hEdit, EM_SETMODIFY, 0, 0); // clear change flag
  752. }
  753.  
  754. //
  755. // QueryWriteFile -- check if buffer has been changed, and if
  756. // so prompt the user to write the file to disk.  
  757. //
  758. VOID QueryWriteFile(HANDLE hEdit)
  759. {
  760.     if(SendMessage(hEdit, EM_GETMODIFY, 0, 0))  // was buffer changed?
  761.     {
  762.         if(MessageBox(hFrame, "File has been changed.  Write file?", 
  763.             szAppName, MB_ICONQUESTION|MB_YESNO) == IDYES)
  764.         {
  765.             SendMessage(hFrame, WM_COMMAND, IDM_SAVEAS, 0);
  766.         }
  767.     }
  768. }
  769.  
  770. //
  771. // SetWindowCaption -- concatenate the filename with the application
  772. // name, then update the frame window's title bar.
  773. //
  774. VOID SetWindowCaption(char * szFilename)
  775. {
  776.     char szTemp[EXENAMESIZE+1];             // filename scratch buffer
  777.  
  778.     strcpy(szTemp, szAppName);              // get application name
  779.     strcat(szTemp, " - ");                  // add separator
  780.     strcat(szTemp, szFileName);             // add filename
  781.     SetWindowText(hFrame, szTemp);          // put result into title bar
  782. }
  783.  
  784.